package conf

import (
	"errors"
	"fmt"
	"gitee.com/lllgo/gopkg/files"
	"gitee.com/lllgo/gopkg/tasks"
	"gitee.com/lllgo/gopkg/utils"
	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"reflect"
	"strings"
)

const (
	MetaKey = "meta"
	FALSE   = "no/0/false"
	EnvsKey = "envs"
	NameKey = "name"
)

// 配置文件的bool值
type ConfigBool interface{}

// 组件配置文件
type ComponentConfig map[string]interface{}

//元数据配置
type MetaConfig struct {
	// 服务器地址 支持服务名数组或服务名用","分隔
	Hosts interface{}
	// 配置本地临时目录
	LocalDir string
	// 是否把命令行参数传递的服务器地址和配置文件配置的hosts合并
	// 如果不合并 命令行参数优先级高于配置文件
	MergeHosts ConfigBool
	// 编排任务
	Tasks []tasks.TaskWrapper
	// 通用参数和服务器独有值参数
	Params, HostParams map[string]interface{}
	// 忽略任务
	IgnoreTasks ConfigBool
}

// 获取组件名
func (cc ComponentConfig) Name() string {
	if tmp, ok := cc[NameKey]; ok {
		return tmp.(string)
	}
	return ""
}

//获取元数据
func (cc ComponentConfig) Meta() MetaConfig {
	var mc MetaConfig
	if err := mapstructure.Decode(cc[MetaKey], &mc); err != nil {
		panic(err)
	}

	mc.LocalDir = utils.GetDefStringWithBool(mc.LocalDir == "", C.LocalDir, files.Abs("", mc.LocalDir))

	if mc.LocalDir == "" {
		panic(errors.New("请设置localDir,本地临时文件存储目录"))
	}
	return mc
}

func (m *MetaConfig) MergeArgsHosts(srcHosts []string) error {
	args := utils.RemoveSliceStringEmptyElement(srcHosts)
	if m.Hosts != nil {
		if Bool(m.MergeHosts, false) {
			if arr, ok := m.Hosts.([]string); ok {
				args = append(args, arr...)
			} else {
				args = append(args, strings.Split(m.Hosts.(string), ",")...)
			}
		} else if len(args) == 0 {
			args = strings.Split(m.Hosts.(string), ",")
		}
	}
	m.Hosts = args

	if len(m.Hosts.([]string)) == 0 {
		return fmt.Errorf("请设置要操作的服务器")
	}

	return nil
}

//获取组件配置文件
func GetComponentConfig(keys ...string) (res []ComponentConfig) {
	key := getConfigKey(keys)
	all := viper.AllSettings()
	logrus.Info("组件配置key", key, all)
	tmp := viper.Get(key)
	logrus.Info("配置文件内容", tmp)
	if tmp != nil {

		// 环境变量支持用","分隔多个环境
		realEnvs := strings.Split(Env, ",")

		//设置环境值为空
		if len(realEnvs) == 0 {
			realEnvs = append(realEnvs, "")
		}

		for _, realEnv := range realEnvs {
			ccs := getPathCC(EnvsKey, realEnv, tmp)
			if l := len(ccs); l > 0 {
				cc := ccs[0]
				if l > 1 {
					for _, c := range ccs[1:] {
						cc = deepOverrideField(cc, c)
					}
				}
				res = append(res, cc)
			}
		}
	}
	logrus.Info("解析的配置属性", res)
	return
}

func writeComponentConfigDeepOverrideField(old, new map[string]interface{}) map[string]interface{} {
	for k, v := range old {
		if tmpNew, okNew := new[k]; okNew {
			if tmp, ok := v.(map[string]interface{}); ok {
				old[k] = writeComponentConfigDeepOverrideField(tmp, getMap(tmpNew))
			} else {
				old[k] = new[k]
			}
		}
	}
	return old
}

func Struct2Map(obj interface{}) map[string]interface{} {
	t := reflect.TypeOf(obj)
	v := reflect.ValueOf(obj)

	var data = make(map[string]interface{})
	for i := 0; i < t.NumField(); i++ {
		fieldData := v.Field(i).Interface()
		if fieldData != nil {
			if reflect.TypeOf(fieldData).Kind() == reflect.Struct {
				data[strings.ToLower(t.Field(i).Name)] = Struct2Map(fieldData)
			} else {
				data[strings.ToLower(t.Field(i).Name)] = fieldData
			}
		}
	}
	return data
}

//把更新后的配置内容写回到配置文件
func WriteComponentConfig(cfg interface{}, keys ...string) {
	key := getConfigKey(keys)
	for _, v := range cacheAllConfigAndViper {
		if data := v.Get(key); data != nil {

			newMap := Struct2Map(cfg)
			oldMap := getMap(data)

			if Env == "" {
				writeComponentConfigDeepOverrideField(oldMap, newMap)
			} else if envs := oldMap[EnvsKey]; envs != nil {
				if arr, ok := envs.([]interface{}); ok {
					for i, env := range arr {
						envMap := getMap(env)
						name := envMap[NameKey]
						if name != nil && name.(string) == Env {
							arr[i] = writeComponentConfigDeepOverrideField(envMap, newMap)
							oldMap[EnvsKey] = arr
							break
						}
					}
				} else {
					envsMap := getMap(envs)
					for name, m := range envsMap {
						if name == Env {
							if m != nil {
								envsMap[name] = writeComponentConfigDeepOverrideField(getMap(m), newMap)
								oldMap[EnvsKey] = envsMap
							}
							break
						}
					}
				}
			}

			v.Set(key, oldMap)
			if err := v.WriteConfig(); err != nil {
				panic(err)
			}
			break
		}
	}
}

func GetConfigPath(keys ...string) string {
	key := getConfigKey(keys)
	for p, v := range cacheAllConfigAndViper {
		if v.Get(key) != nil {
			return p
		}
	}
	return ""
}

//TODO 获取指定配置文件所有有效的
// key为hosts value为env
func GetConfigAllExistsHostEnvs(cfg string, keys ...string) map[string]string {
	var tmp interface{}
	if err := BindConfig(cfg, &tmp, keys...); err != nil || tmp == nil {
		return nil
	}

	res := make(map[string]string, 0)

	//tmpMap := getMap(tmp)

	//for _, tmpCfg := range tmpMap {
	//	if mh,ok :=
	//}

	return res
}

//查找匹配的组件配置，返回由浅到深的组件配置对象数组
func getPathCC(envsKey, realEnv string, cfg interface{}) (ccs []map[string]interface{}) {
	if realEnv != "" {
		if tmp2, ok2 := cfg.([]interface{}); ok2 {
			for _, tmpEnv := range tmp2 {
				tmpMap := getMap(tmpEnv)
				if realEnv == tmpMap[NameKey] {
					ccs = append(ccs, tmpMap)
					return
				} else if tmpEnvs := tmpMap[EnvsKey]; envsKey != EnvsKey && tmpEnvs != nil {
					tmpCCS := getPathCC(envsKey, realEnv, tmpEnvs)
					if len(tmpCCS) > 0 {
						ccs = append(ccs, tmpMap)
						ccs = append(ccs, tmpCCS...)
					}
				} else {
					if envs, ok := tmpMap[envsKey]; ok {
						tmpCCS := getPathCC(realEnv, realEnv, envs)
						if len(tmpCCS) > 0 {
							ccs = append(ccs, tmpMap)
							ccs = append(ccs, tmpCCS...)
						}
					}
				}
			}

		} else {
			tmpMap := getMap(cfg)
			if tmpEnvs, ok := tmpMap[envsKey]; ok {
				if envsKey == realEnv {
					ccs = append(ccs, getMap(tmpEnvs))
					return
				} else {
					ccs = append(ccs, tmpMap)
					ccs = append(ccs, getPathCC(realEnv, realEnv, tmpEnvs)...)
				}
			}
		}
	} else {
		if tmp2, ok2 := cfg.([]interface{}); ok2 {
			ccs = append(ccs, getMap(tmp2[0]))
		} else {
			ccs = append(ccs, getMap(cfg))
		}
	}

	return
}

func getMap(d interface{}) map[string]interface{} {
	if tmp, ok := d.(map[string]interface{}); ok {
		return tmp
	} else if tmpc, ok := d.(ComponentConfig); ok {
		return tmpc
	} else if tmp2, ok2 := d.(map[interface{}]interface{}); ok2 {
		m := make(map[string]interface{})
		for k, v := range tmp2 {
			if tk, ok := k.(string); ok {
				m[tk] = v
			} else {
				panic(fmt.Sprintf("不支持的配置%+v", d))
			}
		}
		return m
	} else {
		panic(fmt.Sprintf("不支持的配置%+v", d))
	}
}

func deepOverrideField(old, new ComponentConfig) ComponentConfig {
	for k, v := range new {
		if k != EnvsKey && v != nil {
			switch reflect.TypeOf(v).Kind() {
			case reflect.Map:
				if tmp := old[k]; tmp != nil {
					old[k] = deepOverrideField(getMap(tmp), getMap(v))
				} else {
					old[k] = v
				}
			default:
				old[k] = v
			}
		}
	}
	return old
}
